<?php
namespace app\api\controller;


use app\admin\model\Lose;
use app\admin\model\Roomclose;
use app\admin\model\Setting;
use app\admin\model\Transaction;
use app\admin\model\user\Balance;
use app\admin\model\user\Extend;
use app\common\library\Tongtongsuo;
use app\common\library\Yunding;
use app\common\library\Reserve as ReserveLib;
use app\common\library\Credit as CreditLib;
use app\common\library\Pay as PayLib;
use app\common\model\Third;
use Carbon\Carbon;
use EasyWeChat\Factory;
use fast\Http;
use tests\thinkphp\library\think\behavior\Three;
use think\Db;
use think\Env;
use think\Log;


class Reserve extends \app\common\controller\Api
{
    protected $noNeedLogin = ['*'];

    protected $_rentAtLeastMin = '';
    protected $_rentReserveAdvanceDay = '';
    protected $_rentRefund = 0;
    protected $_unlockInadvanceMin = 0;
    protected $_declineCredit = 0;
    protected $_refundMoney = 0;
    protected $_cancelRule = '';

    protected function _initialize()
    {
        parent::_initialize();
        $allSettings = Setting::getSettings();
        $this->_rentAtLeastMin = Setting::getSingleSetting('rent_at_least_min', $allSettings);
        $this->_rentReserveAdvanceDay = Setting::getSingleSetting('rent_reserve_advance_day', $allSettings);
        $this->_rentRefund = Setting::getSingleSetting('rent_refund', $allSettings);
        $this->_unlockInadvanceMin = Setting::getSingleSetting('unlock_inadvance_min', $allSettings);
        // 新加的配置
        $this->_rentCancel = Setting::getSingleSetting('rent_cancel', $allSettings);
        $this->_declineCredit = Setting::getSingleSetting('decline_credit', $allSettings);
        $this->_refundMoney = Setting::getSingleSetting('refund_money', $allSettings);
        $this->_cancelRule = Setting::getSingleSetting('cancel_rule', $allSettings);
    }

    public function cancelMyReserve()
    {
        $user = $this->auth->getUser();
        if (null == $user) {
            $this->error('未登录', '', 401);
        }
        $userId = $user->id;

        $id = $this->request->get('id');
        $reserve = \app\admin\model\Reserve::get($id, ['room', 'store']);

        if (!$reserve) {
            $this->error('无预约记录!');
        }

        if ($reserve->user_id != $userId) {
            $this->error('取消异常，非本人的预约!');
        }
        
        if (2 == $reserve->re_status) {
            $this->error('已经取消, 不需重复操作');
        }
        if (Carbon::parse($reserve->starttime)->isBefore(Carbon::now())) {
            $this->error("对不起, 已过预约开始时间，不能取消!");
        }

        if ($this->_rentRefund > 0 && Carbon::parse($reserve->starttime)->subMinutes($this->_rentRefund)->isBefore(Carbon::now())) {
            $tip = $this->_rentRefund . "分钟";
            if ($this->_rentRefund > 60) {
                $hours = intval($this->_rentRefund / 60);
                $minutes = $this->_rentRefund - $hours * 60;
                $tip = $hours . "小时" . $minutes . "分钟";
            }
            $this->error("对不起，临近预约开始时间".$tip."内，不可取消"); 
        }

        if (0 == $this->_rentCancel) {
            $this->error('对不起，当前设置为不可自主取消预约并退款');
        }

        $reserveLib = new ReserveLib($this->_declineCredit, $this->_refundMoney, $this->_rentCancel);
        $ret = $reserveLib->calcCancelReserve($userId, $reserve);

        // 增加确认参数
        $confirm = $this->request->get('confirm', '0');
        $data = [];
        $msg = '当前预约取消成功';
        // 待确认取消
        if ($confirm == '0') {
            $msg = '计算预约成功';
            if ($ret['code'] === 0) {
                $data = $ret['data'];
            }
        } else {
            // 信用分满足确认取消
            if ($ret['code'] === 0) {
                // 有足够的信用分
                if ($ret['data']['pay_money'] === 0) {
                    $declineCredit = $ret['data']['decline_credit'];
                    $code = (new CreditLib())->declineCredit($userId, $declineCredit);
                    if ($code === 1) {
                        $this->error('信用分扣除失败');
                    }
                    $ret = $reserveLib->cancelReserve($userId, $reserve);
                } else {
                    $paymentCtrl = controller('Payment');
                    $paymentCtrl->createTransaction(Transaction::TRANS_TYPE_PUNISH, $ret['data']['pass_reserve_info']);
                }
            } else {
                $ret['code'] = -1;
                $ret['msg'] = '无足够的信用分';
            }
        }
        if ($ret['code'] < 0) {
            $this->error($ret['msg']);
        }
        $this->success($msg, $data);

    }

    public function getMyReserveList()
    {
        $user = $this->auth->getUser();
        if (null == $user) {
            $this->error('未登录', [
                'cancel_rule' => $this->_cancelRule,
                'rent_refund' => $this->_rentRefund,
                'rent_cancel' => $this->_rentCancel,
                'decline_credit' => $this->_declineCredit,
                'refund_money' => $this->_refundMoney,
                'unlock_inadvance_min' => $this->_unlockInadvanceMin,
            ]);
        }
        $userId = $user->id;

        $reserves = \app\admin\model\Reserve::with(['store', 'room'])
            ->where('user_id', $userId)
            ->where('re_status', 1)
            // ->where('endtime', '>', Carbon::now()->toDateTimeString())
            ->where('endtime', '>', Carbon::now()->toDateString())
            ->order('starttime', 'asc')
            ->select();

        $reserves = array_map(function ($e) {
            $e->room_bannerimage = ykxImageUrl($e->room->room_bannerimage);
            return $e;
        }, $reserves);

        $tip = "";
        if ($this->_rentRefund > 0) {
            $tip = $this->_rentRefund . "分钟";
            if ($this->_rentRefund > 60) {
                $hours = intval($this->_rentRefund / 60);
                $minutes = $this->_rentRefund - $hours * 60;
                $tip = $hours . "小时" . $minutes . "分钟";
            }
            $tip = "临近预约开始时间".$tip."内，不可取消";
        }

        $this->success('ok', [
            'reserves' => $reserves,
            'tip' => $tip,
            'cancel_rule' => $this->_cancelRule,
            'rent_refund' => $this->_rentRefund,
            'rent_cancel' => $this->_rentCancel,
            'decline_credit' => $this->_declineCredit,
            'refund_money' => $this->_refundMoney,
            'unlock_inadvance_min' => $this->_unlockInadvanceMin,
        ]);
    }

    public function getMyRecentReserveList()
    {
        $user = $this->auth->getUser();
        if (null == $user) {
            $this->error('未登录');
        }
        $userId = $user->id;

        $reserves = \app\admin\model\Reserve::with(['store', 'room'])
            ->where('user_id', $userId)
            ->where('re_status', 1)
            ->where('endtime', '>', Carbon::now()->subDays(3)->toDateTimeString())
            ->where('endtime', '<', Carbon::now()->toDateTimeString())
            ->select();

        $reserves = array_map(function ($e) {
            $e->room_bannerimage = ykxImageUrl($e->room->room_bannerimage);
            return $e;
        }, $reserves);

        $this->success('ok', [
            'reserves' => $reserves,
        ]);
    }

    public function getOrderTmpPasswd()
    {
        $user = $this->auth->getUser();
        if (null == $user) {
            $this->error('未登录');
        }
        $userExtend = Extend::where('user_id', $user->id)->find();
        if (1 != $userExtend->is_realname) {
            $this->error('必须是实名用户');
        }

        $id = $this->request->get('order_id');

        $reserve = \app\admin\model\Reserve::with(['store', 'room'])
            ->where('id', $id)
            ->find();

        $isUsing = \app\admin\model\Reserve::where('room_id', $reserve->room_id)->where('starttime', '<', Carbon::now()->toDateTimeString())
            ->where('endtime', '>', Carbon::now()->toDateTimeString())
            ->where('re_status', 1)
            ->count();

        $lose = Lose::where('user_id', $user->id)->where('reserve_id', $id)->find();

        if ($isUsing) {
            if ($lose) {
                $lose->count += 1;
                $lose->save();
            } else {
                Lose::create([
                    'user_id' => $user->id,
                    'reserve_id' => $id,
                ]);
            }
            $this->error('教室正在使用，请敲门进入');
        }

        $getPasswd = function() use ($reserve) {
            $yunding = new Yunding();
            // $phoneNumber = $reserve->store->store_mobile ?? Env::get('common.mobile');
            $phoneNumber = Env::get('common.mobile');

            $data = $yunding->addPassword($reserve->room->yunding_homeid, $reserve->room->yunding_uuid, $phoneNumber, Carbon::now()->toDateTimeString(),
                Carbon::now()->addMinutes(5)->toDateTimeString());

            return $data;
        };

        if ($lose) {
            if (empty($lose->passwd) || is_null($lose->passwd_datetime) || Carbon::parse($lose->passwd_datetime)->diffInMinutes(Carbon::now()) > 4) {
                $password = $getPasswd();
                if (false == $password) {
                    $this->error('生成密码失败, 请联系管理员');
                } else {
                    $lose->passwd = $password['password'];
                    $lose->passwd_datetime = Carbon::now()->toDateTimeString();
                }
            }
            $lose->count += 1;
            $lose->save();
            $this->success('ok', $lose->passwd);
        } else {
            $password = $getPasswd();
            if (false == $password) {
                $this->error('生成密码失败, 请联系管理员');
            } else {
                Lose::create([
                    'user_id' => $user->id,
                    'reserve_id' => $id,
                    'passwd' => $password['password'],
                    'passwd_datetime' => Carbon::now()->toDateTimeString()
                ]);
            }
            $this->success('ok', $password['password']);
        }
    }

    public function getMyReserve()
    {
        $id = $this->request->get('id');

        $reserve = \app\admin\model\Reserve::with(['store', 'room'])
            ->where('id', $id)
            ->find();
        $reserve->unlock_inadvance_min = $this->_unlockInadvanceMin;

        $this->success('ok', $reserve);

    }
    
    // 选择支付方式调用 以及 非组合支付时调用
    public function selectPay() 
    {
        $user = $this->auth->getUser();
        if (null == $user) {
            $this->error('未登录', '', 401);
        }
        if (3 == $user->group_id) {
            $this->error('系统当前不能下单');
        }
        $userId = $user->id;
        $post = $this->request->post();
        if (empty($post['pay_type'])) {
            $this->error('还没有选择支付方式');
        }
        if (empty($post['reserve_id'])) {
            $this->error('缺少预约参数');
        }
        $reserve = \app\admin\model\Reserve::where('id', $post['reserve_id'])->lock(true)->find();
        if (!$reserve) {
            $this->error('无预约记录');
        }

        $roomId = $reserve->room_id;
        $roomInfo = model('room')->with('store')->find($roomId);
        if (!$roomInfo || $roomInfo->status != 'normal') {
            $this->error('该房间已下线, 请后退选择其他房间下单');
        }

        $ret = [];
        $reserveLib = new ReserveLib($this->_declineCredit, $this->_refundMoney);

        if ($post['pay_type'] == 'card') {
            if ((empty($post['card_id']) || empty($post['timepills']))) {
                $this->error('选择卡券时缺少必要参数');
            }
            $ret = $reserveLib->cardPay($reserve, $post['card_id'], $post['timepills']);
        } else if ($post['pay_type'] == 'balance') {
            // lock(true) 需要将userExtend表的user_id弄成唯一值
            $userExtend = Extend::where('user_id', $userId)->find();
            $ret = $reserveLib->balancePay($reserve, $userId, $userExtend);
        } else if ($post['pay_type'] == 'wechat') {
            $couponid = $this->request->post('couponid', null);
            $ret = $reserveLib->wechatPay($reserve, $userId, $couponid);
        } else {
            $this->error('无效的支付方式');
        }
        // 非组合的支付
        if (!empty($post['pay_mode']) && $post['pay_mode'] == 1) {
            if (1 == $reserve->re_status) { // fix bug, 在网慢时，用户在前端有可能点了2次请求
                $this->error('预约已经成功，请不要重复请求');
            }
            if ($ret['pay_money'] > 0) {
                $paymentCtrl = controller('Payment');
                $transType = Transaction::TRANS_TYPE_COMBO;
                if ($post['pay_type'] == 'wechat') {
                    $transType = Transaction::TRANS_TYPE_DIRECT_BUY;
                }
                $paymentCtrl->createTransaction($transType, $ret['pass_reserve_info']);
            }
            if ($post['pay_type'] == 'card') {
                $this->selectCardPay($user, $reserve, $ret['card_id']); 
            } else if ($post['pay_type'] == 'balance') {
                $this->selectBalancePay($user, $reserve, $userExtend, $ret['balance']); 
            } else {
                $this->error('无效的支付');
            }

            $this->success('ok');
        }
        $this->success('ok', $ret);
        
    }

    public function otherPay()
    {
        $post = $this->request->post();
        $user = $this->auth->getUser();
        $userId = $user->id ?? 3;

        $roomId = $post['room_id'];
        $roomInfo = model('room')->with('store')->find($roomId);

        $reserve = \app\admin\model\Reserve::get($post['reserve_id']);

        $startTime = Carbon::parse($reserve->starttime);
        $endTime = Carbon::parse($reserve->endtime);

        $startTimeString = $startTime->toDateTimeString();
        $endTimeString = $endTime->toDateTimeString();

        //云丁生成开门的密码

        $yunding = new Yunding();
        // $phoneNumber = $roomInfo->store->store_mobile ?? Env::get('common.mobile');
        $phoneNumber = Env::get('common.mobile');

        $password = $yunding->addPassword($roomInfo->yunding_homeid, $roomInfo->yunding_uuid, $phoneNumber, $startTimeString, $endTimeString);
        if (false == $password) {
            $this->error('智能锁密码下发失败，预约不成功，请联系管理员');
        }

        $couponid = $this->request->post('couponid', null);
        if (is_numeric($couponid) and $couponid > 0) {
            $coupon = \app\admin\model\user\Coupon::get($couponid);
            $coupon->is_used = 1;
            $coupon->save();
        }

        $reserve->re_status = 1;
        $reserve->pay_way = 4; // 2=其它
        $reserve->user_coupon_id = $couponid;
        $reserve->opendoor_pwd = $password['password'];
        $reserve->yunding_password_id = $password['password_id'];
        $reserve->yunding_serviceid = $password['serviceid'];
        $reserve->save();

//        当下时间就是下预约的时间，马上通电
        //    因为crontab电源巡逻是5， 15， 25， 为了避免用户是在预约前5分钟下单，就没有电了
        if (Carbon::now()->betweenIncluded($startTime->subMinutes(6), $endTime)) {
            $yunding->elemeterSwitchOn($roomInfo->yunding_homeid, $roomInfo->yunding_elemetor_uuid);

        }

        $this->success('ok');
    }


    public function getVoucherPayPageInfo()
    {
        $post = $this->request->post();
        $user = $this->auth->getUser();
        $userId = $user->id ?? 3;

        $roomId = $post['room_id'];
        $selectDate = $post['selectdate'];
        $timepills = $post['timepills'];
        $duration = array_reduce($timepills, function ($a, $b) {
            return $a + $b['duration'];
        }, 0);

        $supportCards = \app\common\model\Card::getCouldUseCardList($userId, $selectDate, $duration, $roomId);

        $this->success('ok', $supportCards);

    }


    public function getPayPageInfo()
    {
        $post = $this->request->post();
        $user = $this->auth->getUser();
        if (null == $user) {
            $this->error('未登录', '', 401);
        }
        $userId = $user->id;
        $userExtend = Extend::where('user_id', $userId)->find();
        // 增加实名验证
        if ($userExtend->is_realname == 0) {
            $this->error('未进行实名认证', null, -1);
        }
        // 判断有否满18岁
//        $birth = date('Y-m-d', strtotime(substr($userExtend->id_card, 6, 8)));
//        $birthParse = Carbon::parse($birth);
//        $age = intval($birthParse->diff(Carbon::now())->format('%y'));
//        if ($age < 18) {
//            $this->error('未满18岁，不能预约', null, -1);
//        }

        $roomId = $post['room_id'];
        $selectDate = $post['selectdate'];
        $timepills = $post['timepills'];

        $roomInfo = model('room')->with('store')->find($roomId);
        $curTime = time();
        // 过滤房间状态
        if ($roomInfo->status != 'normal') {
            $this->error('该房间已下线, 请重新选择其他房间');
        }
        if ($roomInfo->store->valid_time < $curTime) {
            $this->error('门店已过期');
        }
        $roomName = $roomInfo->room_name;
        $storeName = $roomInfo->store->store_name;
        $startTime = Carbon::parse($selectDate . ' ' . $timepills[0]['start'] .':00');
        $endTime = Carbon::parse($selectDate . ' ' . $timepills[count($timepills) - 1]['end'] .':00');
        $price = array_reduce($timepills, function ($a, $b) {
            return $a + $b['price'];
        }, 0);
        $duration = array_reduce($timepills, function ($a, $b) {
            return $a + $b['duration'];
        }, 0);

        //是否有合适的卡券
        $supportCards = \app\common\model\Card::getCouldUseCardList($userId, $selectDate, $duration, $roomId);
        $supportCards = array_map(function ($e) {
            return $e->id;
        }, $supportCards);

        //得到用户的余额
        $balance = $userExtend->balance;

        $roomReserves = \app\admin\model\Reserve::where('room_id', $roomId)
            ->whereIn('re_status', [0, 1])
            ->where('starttime', '>', $post['selectdate'] . ' 00:00:00')
            ->where('starttime', '<' , $post['selectdate'] . '23:59:59')
            ->select();

        foreach ($roomReserves as $v) {
            if ($startTime->betweenIncluded($v->starttime, $v->endtime)
                or $endTime->betweenIncluded($v->starttime, $v->endtime)) {
                $this->error('对不起，下单过程中此时间段全部或部分被别人抢占，请返回重新选择');
            }

            if ($startTime->isBefore($v->starttime) and $endTime->isAfter($v->endtime)) {
                $this->error('对不起，下单过程中此时间段全部或部分被别人抢占，请返回重新选择');
            }

            if ($startTime->isAfter($v->starttime) and $endTime->isBefore($v->endtime)) {
                $this->error('对不起，下单过程中此时间段全部或部分被别人抢占，请返回重新选择');
            }
        }


        // 创建订单, 这个订单在创建的状态
        $reserve = \app\admin\model\Reserve::create([
            'trade_no' => (function () {
                list($usec, $sec) = explode(" ", microtime());
                $usec = substr(str_replace('0.', '', $usec), 0 ,4);
                $str  = rand(10,99);
                return date("YmdHis").$usec.$str;
            })(),
            'user_id' => $userId,
            'store_id' => $roomInfo->store_id,
            're_status' => 0, // 创建
            'room_id' => $roomId,
            'starttime' => $startTime->toDateTimeString(),
            'endtime' => $endTime->toDateTimeString(),
            'fee' => $price,
            'createtime' => time(),
            'updatetime' => time()
        ]);

        // 获取门店对应的协议内容
        $agreements = \app\admin\model\Agreement::where('store_type', $roomInfo->store->type)->select();
        $agreeData = [];
        foreach ($agreements as $d) {
            $agreeData[] = [
                'id' => $d['id'],
                'title' => $d['agreement_title'],
            ];
        }

        $this->success('ok', [
            'reserve_id' => $reserve->id,
            'store_name' => $storeName,
            'room_id' => $roomId,
            'selectdate' => $selectDate,
            'timepills' => $timepills,
            'room_name' => $roomName,
            'starttime' => $startTime->toDateTimeString(),
            'endtime' => $endTime->toDateTimeString(),
            'price' => $price,
            'duration' => $duration,
            'support_cards_count' => count($supportCards),
            'balance' => $balance,
            'agree_data' => $agreeData,
        ]);
    }

    public function init()
    {
        $roomId = $this->request->get('roomid');
        $data = [
            'rent_reserve_advance_day' => $this->_rentReserveAdvanceDay,
            'rent_at_least_min' => $this->_rentAtLeastMin,
            'rent_refund' => $this->_rentRefund,
            'rent_time_pills' => $this->_getRentTimePill($roomId, Carbon::now()->toDateString()),
        ];
        $this->success('ok', $data);

    }


    public function getRentTimePill()
    {
        $roomId = $this->request->get('roomid');
        $date = $this->request->get('date');
        $data = $this->_getRentTimePill($roomId, $date);
        $this->success('ok', $data);
    }

    protected function _getRentTimePill($roomId, $date)
    {
        $dateParse = Carbon::parse($date);
        $dateStart = $dateParse->startOfDay()->toDateTimeString();
        $dateEnd = $dateParse->endOfDay()->toDateTimeString();

        //得到当天已经预约的时间
        $reservedTimes = \app\admin\model\Reserve::where('room_id', $roomId)
            ->whereIn('re_status', [0, 1]) //创建和正常
            ->where('starttime', 'between', [$dateStart, $dateEnd])
            ->select();

        $room = \app\common\model\Room::get($roomId);
        $reserveLib = new ReserveLib();
        $rentPills = $reserveLib->getRoomPills($room, $date);
       

        //当时这一段是为了下达智能锁密码时, 如果是过去时间，报错，所以加上的

//        $rentPills = array_filter($rentTime, function ($e) use ($dateParse) {
//            list($hour, $min) = explode(':', $e['end']);
//            $pillend = Carbon::create($dateParse->year, $dateParse->month, $dateParse->day, $hour, $min);
//            if ($pillend->isBefore(Carbon::now())) {
//                return false;
//            } else {
//                return true;
//            }
//        });

        foreach ($rentPills as $k => $item) {
            // 得到这个pill的完整的开始和结束时间，包括的年月日
            list($hour, $min) = explode(':', $item['start']);
            $pillstart = Carbon::create($dateParse->year, $dateParse->month, $dateParse->day, $hour, $min);
            list($hour, $min) = explode(':', $item['end']);
            $pillend = Carbon::create($dateParse->year, $dateParse->month, $dateParse->day, $hour, $min);


            $rentPills[$k]['noon'] = (function ($start) use ($dateParse) {
                if ($start->isBefore(Carbon::create($dateParse->year, $dateParse->month, $dateParse->day, 7, 0))) {
                    return '凌晨';
                } else if ($start->isBefore(Carbon::create($dateParse->year, $dateParse->month, $dateParse->day, 12, 0))) {
                    return '上午';
                } else if ($start->isBefore(Carbon::create($dateParse->year, $dateParse->month, $dateParse->day, 19, 0))) {
                    return '下午';
                } else {
                    return '晚上';
                }
            })($pillstart);
            $rentPills[$k]['id'] = $k;
            // if ($pillend->hour == 23 and $pillend->minute == 59) { //防止  00：00 和 23:59时，缺少一分钟
            if ($pillend->minute == 29 || $pillend->minute == 59) { //防止  00：00 和 23:59时，缺少一分钟
                $rentPills[$k]['duration'] = $pillend->diffInMinutes($pillstart) + 1;
            } else {
                $rentPills[$k]['duration'] = $pillend->diffInMinutes($pillstart);
            }
            
            $rentPills[$k]['state'] = 0;
            // 兼容老数据
            $isOpen = isset($item['is_open']) ? $item['is_open'] : '1';
            if ($isOpen === '0') {
                $rentPills[$k]['state'] = 2;
                $rentPills[$k]['user_id'] = 0;
                continue;
            }

            // 如果这个pill开始和结果时间之间有$reserveTimes的开始和结束时间，那么这个pill的state设置为2
            foreach ($reservedTimes as $reservedTime) {
                $reserveStartTime = Carbon::parse($reservedTime->starttime)->addMinute();
                $reserveEndTime = Carbon::parse($reservedTime->endtime)->subMinute();
                if ($reserveStartTime->betweenIncluded($pillstart, $pillend)) {
                    $rentPills[$k]['state'] = 2; // 2 表示已经占用了
                    $rentPills[$k]['user_id'] = $reservedTime->user_id;
                } else if ($reserveEndTime->betweenIncluded($pillstart, $pillend)) {
                    $rentPills[$k]['state'] = 2;
                    $rentPills[$k]['user_id'] = $reservedTime->user_id;
                } else if ($reserveStartTime->isBefore($pillstart)
                    and $reserveEndTime->isAfter($pillend)) {
                    $rentPills[$k]['state'] = 2;
                    $rentPills[$k]['user_id'] = $reservedTime->user_id;
                }
            }
        }

        $rentPills = array_values($rentPills); // 防止key 不是从0开始，会在js的客户端当成对象解释

        return $rentPills;

    }

    public function delete()
    {
        $id = $this->request->post('id');

        $reserve = \app\admin\model\Reserve::get($id);
        if (0 == $reserve->re_status) {
            $result = $reserve->delete();
            if ($result) {
                $this->success('ok');
            } else {
                $this->error('删除失败');
            }
        } else {
            $this->error('非创建状态，不能删除');
        }

    }

    private function createRoomYundingPasswd($roomInfo, $startTime, $endTime)
    {
        $yunding = new Yunding();
        // $phoneNumber = $roomInfo->store->store_mobile ?? Env::get('common.mobile');
        $phoneNumber = Env::get('common.mobile');

        $unlockInAdvanceMin = Setting::getUnlockInadvanceMin();
        if ($unlockInAdvanceMin > 0) {
            $startTime->subMinutes($unlockInAdvanceMin);
        }

        $password = $yunding->addPassword($roomInfo->yunding_homeid, $roomInfo->yunding_uuid, $phoneNumber, $startTime->toDateTimeString(), $endTime->toDateTimeString());
        if (false == $password) {
            $this->error('智能锁密码下发失败，预约不成功，请联系管理员');
        } else {
            return $password;
        }
    }

    private function setYunding($roomInfo, $startTime, $endTime)
    {
        $yunding = new Yunding();
        //当下时间就是下预约的时间，马上通电
        //    因为crontab电源巡逻是5， 15， 25， 为了避免用户是在预约前5分钟下单，就没有电了
        Log::write('setYunding =>' . $endTime->toDateTimeString());

        if (Carbon::now()->betweenIncluded($startTime->subMinutes(6), $endTime)) {
            $yunding->elemeterSwitchOn($roomInfo->yunding_homeid, $roomInfo->yunding_elemetor_uuid);
            if (!empty($roomInfo->yunding_elemetor_uuid2)) {
                $yunding->elemeterSwitchOn($roomInfo->yunding_homeid, $roomInfo->yunding_elemetor_uuid2);
            }
        }
  
    }

    private function selectCardPay($user, $reserve, $cardId)
    {
        $roomId = $reserve->room_id;
        $roomInfo = model('room')->with('store')->find($roomId);

        $startTime = Carbon::parse($reserve->starttime);
        $endTime = Carbon::parse($reserve->endtime);

        if ($endTime->minute == 29 || $endTime->minute == 59) {
            $endTime->addMinute();
        }
        $consumeHour = number_format($endTime->diffInMinutes($startTime) / 60, 2);

        Db::startTrans();

        try {
            $userId = $user->id;
            // 进行支付
            $payLib = new PayLib($userId, $reserve->id);
            $payLib->cardPay($cardId, $consumeHour);

            $yundingPwd = $this->createRoomYundingPasswd($roomInfo, $startTime, $endTime);

            $reserveLib = new ReserveLib($this->_declineCredit, $this->_refundMoney);
            $payData = [
                'pay_way' => 1,
                'field_name' => 'card_id',
                'field_val' => $cardId,
            ];
            $reserveLib->updateReserve($reserve, $payData, $yundingPwd);
            $this->setYunding($roomInfo, $startTime, $endTime);

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
    
    }

    private function selectBalancePay($user, $reserve, $userExtend, $subNum)
    {
        $roomId = $reserve->room_id;
        $roomInfo = model('room')->with('store')->find($roomId);

        $startTime = Carbon::parse($reserve->starttime);
        $endTime = Carbon::parse($reserve->endtime);

        if ($endTime->minute == 29 || $endTime->minute == 59) {
            $endTime->addMinute();
        }

        Db::startTrans();

        try {
            $userId = $user->id;
            // 进行支付
            $payLib = new PayLib($userId, $reserve->id);
            $balanceId = $payLib->balancePay($subNum, $userExtend);
            if (empty($balanceId)) {
                throw new \Exception('余额扣除失败');
            }

            $couponid = $this->request->post('couponid', null);
            $payLib->couponPay($couponid);

            //通通锁生成开门的密码
            $yundingPwd = $this->createRoomYundingPasswd($roomInfo, $startTime, $endTime);

            $reserveLib = new ReserveLib($this->_declineCredit, $this->_refundMoney);
            $payData = [
                'pay_way' => 2,
                'field_name' => 'balance_id',
                'field_val' => $balanceId,
            ];
            $reserveLib->updateReserve($reserve, $payData, $yundingPwd, $couponid);

            $this->setYunding($roomInfo, $startTime, $endTime);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
    
    }

    private function _checkSignFromTuyuFeiniao()
    {
        $time = input('get.time');
        $sign = input('get.sign');
        $createSign = md5($time . 'tuzi_gaden2025');
        if ($sign != $createSign) {
            $this->error('签名错误');
        }
    }

    public function openRoomRentTimePill()
    {
        $this->_checkSignFromTuyuFeiniao();
        $roomId = $this->request->get('gaden_roomid');
        $date = $this->request->get('date');
        $data = $this->_getRentTimePill($roomId, $date);
        $this->success('ok', $data);
    }

    public function openLockRoom()
    {
        $this->_checkSignFromTuyuFeiniao();
        $post = $this->request->post();
        $userId = 5077;  //第三方下的单，都为5077用户下的单位

        $roomId = $post['gaden_roomid'];
        $selectDate = $post['selectdate'];
        $timepills = $post['timepills'];

        $roomInfo = model('room')->with('store')->find($roomId);
        $curTime = time();
        // 过滤房间状态
        if ($roomInfo->status != 'normal') {
            $this->error('该房间已下线, 请重新选择其他房间');
        }
        if ($roomInfo->store->valid_time < $curTime) {
            $this->error('门店已过期');
        }
        $roomName = $roomInfo->room_name;
        $storeName = $roomInfo->store->store_name;
        $startTime = Carbon::parse($selectDate . ' ' . $timepills[0]['start'] .':00');
        $endTime = Carbon::parse($selectDate . ' ' . $timepills[count($timepills) - 1]['end'] .':00');
        $price = array_reduce($timepills, function ($a, $b) {
            return $a + $b['price'];
        }, 0);
        $duration = array_reduce($timepills, function ($a, $b) {
            return $a + $b['duration'];
        }, 0);

        //是否有合适的卡券
        $supportCards = \app\common\model\Card::getCouldUseCardList($userId, $selectDate, $duration, $roomId);
        $supportCards = array_map(function ($e) {
            return $e->id;
        }, $supportCards);

        $roomReserves = \app\admin\model\Reserve::where('room_id', $roomId)
            ->whereIn('re_status', [0, 1])
            ->where('starttime', '>', $post['selectdate'] . ' 00:00:00')
            ->where('starttime', '<' , $post['selectdate'] . '23:59:59')
            ->select();

        foreach ($roomReserves as $v) {
            if ($startTime->betweenIncluded($v->starttime, $v->endtime)
                or $endTime->betweenIncluded($v->starttime, $v->endtime)) {
                $this->error('对不起，下单过程中此时间段全部或部分被别人抢占，请返回重新选择');
            }

            if ($startTime->isBefore($v->starttime) and $endTime->isAfter($v->endtime)) {
                $this->error('对不起，下单过程中此时间段全部或部分被别人抢占，请返回重新选择');
            }

            if ($startTime->isAfter($v->starttime) and $endTime->isBefore($v->endtime)) {
                $this->error('对不起，下单过程中此时间段全部或部分被别人抢占，请返回重新选择');
            }
        }


        // 创建订单, 这个订单在创建的状态
        $reserve = \app\admin\model\Reserve::create([
            'trade_no' => (function () {
                list($usec, $sec) = explode(" ", microtime());
                $usec = substr(str_replace('0.', '', $usec), 0 ,4);
                $str  = rand(10,99);
                return date("YmdHis").$usec.$str;
            })(),
            'user_id' => $userId,
            'store_id' => $roomInfo->store_id,
            're_status' => 0, // 创建
            'room_id' => $roomId,
            'starttime' => $startTime->toDateTimeString(),
            'endtime' => $endTime->toDateTimeString(),
            'fee' => $price,
            'createtime' => time(),
            'updatetime' => time()
        ]);

        $this->success('ok', [
            'reserve_id' => $reserve->id,
            'store_name' => $storeName,
            'room_id' => $roomId,
            'selectdate' => $selectDate,
            'timepills' => $timepills,
            'room_name' => $roomName,
            'starttime' => $startTime->toDateTimeString(),
            'endtime' => $endTime->toDateTimeString(),
            'price' => $price,
            'duration' => $duration,
        ]);
    }

    public function openReserveRoom()
    {
        $this->_checkSignFromTuyuFeiniao();
        $userId = 5077;
        $user = \app\admin\model\User::get($userId);
        $post = $this->request->post();
        $post['pay_type'] = 'balance';
        if (empty($post['reserve_id'])) {
            $this->error('缺少预约参数');
        }
        $reserve = \app\admin\model\Reserve::where('id', $post['reserve_id'])->lock(true)->find();
        if (!$reserve) {
            $this->error('无预约记录');
        }

        $roomId = $reserve->room_id;
        $roomInfo = model('room')->with('store')->find($roomId);
        if (!$roomInfo || $roomInfo->status != 'normal') {
            $this->error('该房间已下线, 请后退选择其他房间下单');
        }

        $ret = [];
        $reserveLib = new ReserveLib(0, 0);

        // lock(true) 需要将userExtend表的user_id弄成唯一值
        $userExtend = Extend::where('user_id', $userId)->find();
        $ret = $reserveLib->balancePay($reserve, $userId, $userExtend);
        // 非组合的支付
        if (1 == $reserve->re_status) { // fix bug, 在网慢时，用户在前端有可能点了2次请求
            $this->error('预约已经成功，请不要重复请求');
        }

        $this->selectBalancePay($user, $reserve, $userExtend, $ret['balance']);

        $this->success('ok');
    }

    public function openCancelReserve()
    {
        $this->_checkSignFromTuyuFeiniao();
        $userId = 5077;

        $id = $this->request->post('reserve_id');
        $reserve = \app\admin\model\Reserve::get($id, ['room', 'store']);

        if (!$reserve) {
            $this->error('无预约记录!');
        }

        if ($reserve->user_id != $userId) {
            $this->error('取消异常，非本人的预约!');
        }

        if (2 == $reserve->re_status) {
            $this->error('已经取消, 不需重复操作');
        }
//        if (Carbon::parse($reserve->starttime)->isBefore(Carbon::now())) {
//            $this->error("对不起, 已过预约开始时间，不能取消!");
//        }

        $reserveLib = new ReserveLib(0, 0, 0);

        // 增加确认参数
        $data = [];
        $msg = '当前预约取消成功';
        $reserveLib->cancelReserve($userId, $reserve);
        $this->success($msg, $data);

    }

    public function openDelete()
    {
        $this->_checkSignFromTuyuFeiniao();
        $id = $this->request->post('reserve_id');

        $reserve = \app\admin\model\Reserve::get($id);
        if (0 == $reserve->re_status) {
            $result = $reserve->delete();
            if ($result) {
                $this->success('ok');
            } else {
                $this->error('删除失败');
            }
        } else {
            $this->error('非创建状态，不能删除');
        }
    }

    public function openGetReserve()
    {
        $this->_checkSignFromTuyuFeiniao();
        $id = $this->request->get('reserve_id');

        $reserve = \app\admin\model\Reserve::get($id);

        $this->success('ok', $reserve);
    }

    public function openGetOrderTmpPasswd()
    {
        $this->_checkSignFromTuyuFeiniao();

        $userId = 5077;

        $id = $this->request->get('reserve_id');

        $reserve = \app\admin\model\Reserve::with(['store', 'room'])
            ->where('id', $id)
            ->find();

        $isUsing = \app\admin\model\Reserve::where('room_id', $reserve->room_id)->where('starttime', '<', Carbon::now()->toDateTimeString())
            ->where('endtime', '>', Carbon::now()->toDateTimeString())
            ->where('re_status', 1)
            ->count();

        $lose = Lose::where('user_id', $userId)->where('reserve_id', $id)->find();

        if ($isUsing) {
            if ($lose) {
                $lose->count += 1;
                $lose->save();
            } else {
                Lose::create([
                    'user_id' => $userId,
                    'reserve_id' => $id,
                ]);
            }
            $this->error('教室正在使用，请敲门进入');
        }

        $getPasswd = function() use ($reserve) {
            $yunding = new Yunding();
            // $phoneNumber = $reserve->store->store_mobile ?? Env::get('common.mobile');
            $phoneNumber = Env::get('common.mobile');

            $data = $yunding->addPassword($reserve->room->yunding_homeid, $reserve->room->yunding_uuid, $phoneNumber, Carbon::now()->toDateTimeString(),
                Carbon::now()->addMinutes(5)->toDateTimeString());

            return $data;
        };

        if ($lose) {
            if (empty($lose->passwd) || is_null($lose->passwd_datetime) || Carbon::parse($lose->passwd_datetime)->diffInMinutes(Carbon::now()) > 4) {
                $password = $getPasswd();
                if (false == $password) {
                    $this->error('生成密码失败, 请联系管理员');
                } else {
                    $lose->passwd = $password['password'];
                    $lose->passwd_datetime = Carbon::now()->toDateTimeString();
                }
            }
            $lose->count += 1;
            $lose->save();
            $this->success('ok', $lose->passwd);
        } else {
            $password = $getPasswd();
            if (false == $password) {
                $this->error('生成密码失败, 请联系管理员');
            } else {
                Lose::create([
                    'user_id' => $userId,
                    'reserve_id' => $id,
                    'passwd' => $password['password'],
                    'passwd_datetime' => Carbon::now()->toDateTimeString()
                ]);
            }
            $this->success('ok', $password['password']);
        }
    }


}
